﻿using System;
using System.Collections.Generic;
using FinanSoft.Entities;
using FinanSoft.Utilities;
using FinanSoft.DataLayer;

namespace FinanSoft.BusinessLayer
{
    class PaymentManager
    {

        #region Atributos
        /// <summary>
        /// Única instancia de esta clase
        /// </summary>
        private static PaymentManager _instance;
        private bool _IsError;
        private String _ErrorMessage;
        #endregion

        #region Constructor singleton
        private PaymentManager()
        {
            _IsError = false;
            _ErrorMessage = "";
        }         
        
        /// <summary>
        /// Método para implementar el patrón de Singleton
        /// </summary>
        /// <returns>Instancia única de la clase</returns>
        public static PaymentManager GetInstance()
        {
            if (_instance == null)
                _instance = new PaymentManager();
            return _instance;
        }
        #endregion

        #region Propiedades
        public bool IsError
        {
            get
            {
                bool temp = _IsError;
                _IsError = false;
                return temp;
            }
        }

        public String ErrorMessage
        {
            get
            {
                String temp = _ErrorMessage;
                _IsError = false;
                _ErrorMessage = "";
                return temp;
            }
        }
        #endregion

        #region Métodos
        /// <summary>
        /// Realiza el pago de las facturas. Esto incluye hacer los asientos contables correspondientes y registrar las transferencias
        /// en la base de datos. 
        /// </summary>
        /// <param name="bills">Facturas que se quieren cancelar</param>
        /// <param name="bankingAccount">Cuenta bancaria contra las que se cancelan las facturas</param>
        /// <param name="billOwnerCode">Indica si las facturas son del cliente o del proveedor. Ver constantes IS_CLIENT e IS_PROVIDER</param>
        /// <returns>Indica si se pudo realizar la operación o no. Si hubo un error se guarda en ErrorMessage(atributo de clase)</returns>
        public bool RealizePayment(List<OpenDocument> bills, Account bankingAccount, int billOwnerCode)
        {
            // Calculamos el subtotal que habría que pagar de las facturas que selecciona el usuario
            double localTotal = 0;
            double systemTotal = 0;
            List<AccountingEntryDetail> transactionDetails = new List<AccountingEntryDetail>();
            foreach(OpenDocument openDoc in bills)
            {
                Constants.AccountingEntryType incType = billOwnerCode == Constants.IS_CLIENT_CODE ? Constants.AccountingEntryType.credit : Constants.AccountingEntryType.debit;
                Currency documentCurrency = openDoc.Currency;
                double localAmount = Math.Round(openDoc.monto * documentCurrency.ToLocalCurrency, 2);
                double systemAmount = Math.Round(localAmount / MoneyManager.GetInstance().SystemCurrency.ToLocalCurrency, 2);
                if (openDoc.tipoDocumento == Constants.NC_ACCOUNTING_ENTRY)
                {
                    incType = Constants.AccountingEntryType.debit;
                    localTotal -= localAmount;
                    systemTotal -= systemAmount;
                }
                else
                {
                    localTotal += localAmount;
                    systemTotal += systemAmount;
                }
                transactionDetails.Add(
                    AccountingEntryManager.GetInstance().BuildAccountingEntryDetail(
                        openDoc.DocumentOwner.Parent, systemAmount, localAmount,
                        incType, openDoc.DocumentOwner.AccountID));
            }
            // Cancelo todas las facturas contra la cuenta bancaria
            Constants.AccountingEntryType bankInc = billOwnerCode == Constants.IS_CLIENT_CODE ? Constants.AccountingEntryType.debit : Constants.AccountingEntryType.credit;
            if (localTotal < 0)
            {
                localTotal *= -1;
                systemTotal *= -1;
                bankInc = Constants.AccountingEntryType.credit;
            }
            transactionDetails.Add(
                AccountingEntryManager.GetInstance().BuildAccountingEntryDetail(
                            bankingAccount.AccountID, systemTotal, localTotal,
                            bankInc, Constants.INVALID_ID));
            AccountingPeriod period = PeriodManager.GetInstance().GetCurrentAccountingPeriod();
            if(period == null)
            {
                _IsError = true;
                _ErrorMessage = Constants.NO_CURRENT_PERIOD_ESTABLISHED;
                return false;
            }
            else if(period.GetCurrentSeason() == null)
            {
                _IsError = true;
                _ErrorMessage = Constants.NO_CURRENT_SEASON_ESTABLISHED;
                return false;
            }
            else
            {
                bool result = AccountingEntryManager.GetInstance().CreateAndRecordAccountingEntry(
                billOwnerCode == Constants.IS_CLIENT_CODE ? Constants.PR_ACCOUNTING_ENTRY : Constants.PE_ACCOUNTING_ENTRY,
                DateTime.Now, DateTime.Now, period.GetCurrentSeason().Id, Constants.PAYMENT_REFERENCE, "", "", transactionDetails); 
                if(!result)
                {
                    _IsError = true;
                    _ErrorMessage = AccountingEntryManager.GetInstance().ErrorMessage;
                    return false;
                }
                // Guardamos las transferencias
                if(!OpenDocumentDataManager.GetInstance().CancelDocuments(bills, bankingAccount, billOwnerCode))
                {
                    _IsError = true;
                    _ErrorMessage = Constants.TRANSFER_ERROR;
                    return false;
                }
                return true;
            }
        }
        #endregion
    }
}
